/**
 * @file BisectionSolver.h
 * @brief 
 * @author htli (3180102114@zju.edu.cn)
 * @version 1.0
 * @date 2021-10-03
 * 
 * @copyright Copyright (c) 2021  linhuo2020
 * 
 */
#ifndef _PRO1_BISECTIONSOLVER_
#define _PRO1_BISECTIONSOLVER_
#include "EquationSolver.h"

class BisectionSolver : public EquationSolver
{
protected:
    const std::string Name = "Bisection Method";
    double min_width = 1e-10;

public:
    using EquationSolver::EquationSolver;
    void set_min_width(const double _min) { min_width = _min; };
    const double solve()
    {
        int k = 0;
        double x0 = init[0];
        double x1 = init[1];
        if (x0 > x1)
        {
            double temp = x0;
            x0 = x1;
            x1 = temp;
        };
        double h = x1 - x0;
        double u = (*pf)(x0);
        double w;
        double mid;
        for (k = 0; (k <= max_iteration); k++)
        {
            h /= 2;
            mid = x0 + h;
            w = (*pf)(mid);
            if ((fabs(h) < 1e-10) || (fabs(w) < tolerance))
            {
                break;
            }
            else if ((w * u) >= 0)
            {
                x0 = mid;
            };
        };
        if ((fabs(h) < min_width)&&(fabs(w)>tolerance))
        {
            std::cout << "Warning: The given tolerance " << tolerance << " cannot be reached, because the width of interval is less than " << min_width << " in " << k << " steps." << std::endl;
            std::cout << "The ouput is " << x0 << ", with f(x0) = " << fabs((*pf)(x0)) << "." << std::endl;
        }
        else if ((k <= max_iteration))
        {
            std::cout << "By " << Name.c_str() << ", the solution is " << x0 << ", in " << k << " steps, with tolerance of " << tolerance << "." << std::endl;
        }
        else
        {
            std::cout << "Warning: The given tolerance " << tolerance << " cannot be reached in " << max_iteration << " steps" << std::endl;
            std::cout << "The ouput is " << x0 << ", with f(x) =  " << fabs((*pf)(x0)) << "." << std::endl;
        };
        return x0;
    };
};

#else
//DO NOTHING
#endif